package cn.springcloud.fix.quartz.config;

import cn.springcloud.fix.quartz.arithmetic.ArithmeticTaskAdapter;
import cn.springcloud.fix.quartz.arithmetic.TaskAdapterComposite;
import cn.springcloud.fix.quartz.dao.entity.SysJob;
import cn.springcloud.fix.quartz.dao.entity.SysJobLog;
import cn.springcloud.fix.quartz.dao.mapper.SysJobLogMapper;
import cn.springcloud.fix.quartz.dao.mapper.SysJobMapper;
import cn.springcloud.fix.quartz.service.ScheduleService;
import lombok.extern.slf4j.Slf4j;
import org.quartz.*;
import org.springframework.beans.factory.InitializingBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.quartz.QuartzJobBean;
import org.springframework.stereotype.Component;

import java.util.List;

@Slf4j
@Component
public class QuartzManager extends QuartzJobBean implements InitializingBean {

    private final TaskAdapterComposite taskAdapterComposite = new TaskAdapterComposite();

    /**
     * job参数key
     */
    public static final String JOB_PARAM_KEY = "PARAM_KEY";

    public static final String CORN_EXPRESSION = "CORN_EXPRESSION";

    @Autowired
    private SysJobMapper sysJobMapper;

    @Autowired
    private SysJobLogMapper sysJobLogMapper;

    @Autowired
    private ScheduleService scheduleService;

    @Autowired
    private List<ArithmeticTaskAdapter> arithmeticTaskAdapterList;

    @Override
    protected void executeInternal(JobExecutionContext jobExecutionContext) {
        long beginTime = System.currentTimeMillis();
        SysJobLog sysJobLog = new SysJobLog();
        try {
            JobDataMap jobDataMap = jobExecutionContext.getJobDetail().getJobDataMap();
            Long jobId = (Long) jobDataMap.get(QuartzManager.JOB_PARAM_KEY);
            String cronExpression = (String) jobDataMap.get(QuartzManager.CORN_EXPRESSION);
            if (jobId == null || cronExpression == null) return;

            SysJob sysJob = sysJobMapper.selectById(jobId);
            if (sysJob == null) return;
            if (1 != sysJob.getJobStatus()) return;

            //cron表达式和数据库不一致的情况，就去重新创建任务
            if (!sysJob.getCronExpression().trim().equals(cronExpression.trim())) {
                scheduleService.reBuildJobTask(jobId.toString(), sysJob.getJobGroup(), sysJob.getCronExpression());
                return;
            }

            sysJobLog.setJobId(jobId);
            sysJobLog.setJobName(sysJob.getName());
            sysJobLog.setJobGroup(sysJob.getJobGroup());

            preExecute(jobExecutionContext);
            executeJob(jobExecutionContext, sysJob);
            postExecute(jobExecutionContext);

            sysJobLog.setStatus(0);
        } catch (Exception e) {
            log.error(e.getMessage(), e);
            sysJobLog.setStatus(-1);
            sysJobLog.setRemark(e.getMessage());

            postExecute(jobExecutionContext);
        } finally {
            long endTime = System.currentTimeMillis();
            if (null != jobExecutionContext.getFireTime()) {
                sysJobLog.setFireTime(jobExecutionContext.getFireTime());
            }
            if (null != jobExecutionContext.getNextFireTime()) {
                sysJobLog.setNextFireTime(jobExecutionContext.getNextFireTime());
            }
            sysJobLog.setDuration(endTime - beginTime);
            sysJobLogMapper.insert(sysJobLog);
        }
    }

    private void preExecute(JobExecutionContext context) {
        log.info("preExecute..............");
    }

    private void executeJob(JobExecutionContext jobExecutionContext, SysJob sysJob) throws Exception {
        if (taskAdapterComposite.supportTask(sysJob.getId())) {
            taskAdapterComposite.handleTask(sysJob);
        }
        //ArithmeticTask arithmeticTask = SpringUtil.getContext().getBean(sysJob.getId(), ArithmeticTask.class);
        //arithmeticTask.runJob();
        // Method method = obj.getClass().getMethod(sysJob.getJobMethod());
        // method.invoke(obj);
    }

    private void postExecute(JobExecutionContext context) {
        log.info("postExecute..............");
    }

    @Override
    public void afterPropertiesSet() {
        if (this.taskAdapterComposite.getTaskAdapterList().isEmpty()) {
            this.taskAdapterComposite.addAdapters(arithmeticTaskAdapterList);
        }
    }
}
